#pragma once
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include "Logger.hpp"

const static std::string sep = "\r\n";
const static std::string sep1 = " ";
const static std::string sep2 = ": ";
const static std::string webroot = "./wwwroot";
const static std::string defaulthome = "index.html";

class HttpRequest
{
private:
    std::string ReadOneLine(std::string &reqstr, bool *status)
    {
        auto pos = reqstr.find(sep);
        if (pos == std::string::npos)
        {
            *status = false;
            return std::string();
        }
        *status = true;
        std::string line = reqstr.substr(0, pos);
        reqstr.erase(0, pos + sep.size());
        return line;
    }
    void ParseReqline(const std::string &reqline)
    {
        std::stringstream ss(reqline);
        ss >> _method >> _uri >> _http_version;
    }
    void BuildKV(const std::string &reqline, std::string *k, std::string *v)
    {
        auto pos = reqline.find(sep2);
        if (pos = std::string::npos)
        {
            *k = *v = std::string();
            return;
        }
        *k = reqline.substr(0, pos);
        *v = reqline.substr(pos + sep2.size());
    }

public:
    HttpRequest() {}
    // bool Serialize()
    // {
    //     // 不用序列化，因为浏览器会发起请求帮我们做序列化
    // }
    bool DeSerialize(std::string &reqstr)
    {
        bool status = true;
        std::string reqline = ReadOneLine(reqstr, &status);
        if (!status)
            return false;
        // LOG(LogLevel::DEBUG) << reqline;
        ParseReqline(reqline);
        while (true)
        {
            status = true;
            reqline = ReadOneLine(reqstr, &status);
            if (status && !reqline.empty())
            {
                std::string k, v;
                BuildKV(reqline, &k, &v);
                if (k.empty() || v.empty())
                    continue;
                _req_hander.insert(std::make_pair(k, v));
            }
            else if (status)
            {
                _blank_line = sep;
                break;
            }
            else
            {
                LOG(LogLevel::DEBUG) << "非法请求";
                break;
            }
        }

        _req_body = reqstr;

        _path = webroot;
        _path += _uri;
        if (_uri == "/")
        {
            _path += defaulthome;
        }
        LOG(LogLevel::DEBUG) << "_path: " << _path;

        return true;
    }

    std::string Path()
    {
        return _path;
    }
    ~HttpRequest() {}

private:
    std::string _method;
    std::string _uri;
    std::string _http_version;
    std::unordered_map<std::string, std::string> _req_hander;
    std::string _blank_line;
    std::string _req_body;

    std::string _path;
};

class HttpResponse
{
public:
    HttpResponse() : _http_version("HTTP/1.1"), _blank_line(sep) {}
    std::string Serialize()
    {
        std::stringstream ss;
        ss << _code;
        std::string respstr = _http_version + sep1 + ss.str() + sep1 + _code_des + sep;
        for (auto &e : _resp_hander)
        {
            std::string line = e.first + sep2 + e.second + sep;
            respstr += line;
        }
        respstr += _blank_line;
        respstr += _resp_body;
        return respstr;
    }
    // bool DeSerialize()
    // {
    //     // 不用反序列化，因为浏览器会相应请求，帮我们反序列化
    // }
    void ReadContent(const std::string &path)
    {
        // ⼀份简单的读取⼆进制⽂件的代码
        std::ifstream in(path, std::ios::binary);
        if (!in.is_open())
            return;
        in.seekg(0, in.end);
        int filesize = in.tellg();
        in.seekg(0, in.beg);
        
        _resp_body.resize(filesize);
        in.read((char *)_resp_body.c_str(), filesize);
        // std::vector<char> content(filesize);
        // in.read(content.data(), filesize);
        in.close();
        this->setHeader("Content-Length",std::to_string(filesize));
    }
    void setHeader(const std::string& key,const std::string& value){
        _resp_hander[key] = value;
    }

    void SetCode(int code, const std::string &desc)
    {
        _code = code;
        _code_des = desc;
    }
    ~HttpResponse() {}
private:
    std::string _http_version;
    std::string _code;
    std::string _code_des;
    std::unordered_map<std::string, std::string> _resp_hander;
    std::string _blank_line;
    std::string _resp_body;
};

class Http
{
public:
    Http() {}
    std::string PackUp(std::string &reqstr)
    {
        std::string respstr;
        HttpRequest req;
        if (req.DeSerialize(reqstr))
        {
            HttpResponse resp;
            resp.ReadContent(req.Path());
            resp.SetCode(200, "OK");
            resp.setHeader("Content-Type", "text/html");
            respstr = resp.Serialize();
        }
        return respstr;
    }
    ~Http() {}

private:
};
